/*
 * Android-PercentProgressBar
 * Copyright (c) 2015  Natasa Misic
 *
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package com.natasa.progresspercent.lib;

import ohos.agp.components.Attr;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.BlurDrawLooper;
import ohos.agp.render.Paint;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.app.Environment;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * 基类
 *
 * @since 2021-07-14
 */
abstract class BaseProgressView extends Component {
    /**
     * BYTE
     */
    public static final int BYTE = 1024;
    /**
     * 默认半径
     */
    public static final float DEFAULT_RADIUS = 3.0f;
    /**
     * DEFAULT_NUMBER
     */
    public static final int DEFAULT_NUMBER = -1;
    /**
     * 最大进度
     */
    protected int maxProgress = 100;
    /**
     * 前景画笔
     */
    protected Paint foregroundPaint;
    /**
     * 背景画笔
     */
    protected Paint backgroundPaint;
    /**
     * 文字画笔
     */
    protected Paint textPaint;
    /**
     * 背景画笔宽度
     */
    protected float backgroundStrokeWidth = DEFAULT_RADIUS;
    /**
     * 画笔宽度
     */
    protected float strokeWidth = 5f;
    /**
     * padding
     */
    protected float padding = 20;
    /**
     * 颜色
     */
    protected Color color = new Color(Color.getIntColor("#FF4081"));
    /**
     * 背景色
     */
    protected Color backgroundColor = Color.WHITE;
    /**
     * 文本颜色
     */
    protected Color textColor = new Color(Color.getIntColor("#0097A7"));
    /**
     * 阴影颜色
     */
    protected Color shadowColor = new Color(Color.getIntColor("#33000000"));
    /**
     * 字体大小
     */
    protected int textSize = 26;
    /**
     * 字体
     */
    protected Font typeFace;
    /**
     * 字体名称
     */
    protected String facePath = "Roboto-Light.ttf";
    /**
     * 上下文
     */
    protected Context mContext;
    /**
     * 是否设置round
     */
    protected boolean isRoundEdge;
    /**
     * 是否显示阴影
     */
    protected boolean isShadowed;
    /**
     * 进度监听
     */
    protected OnProgressTrackListener listener;
    /**
     * 高
     */
    protected int height;
    /**
     * 宽
     */
    protected int width;
    /**
     * 进度
     */
    protected int progress;
    private final HiLogLabel mTag = new HiLogLabel(HiLog.LOG_APP, 0, getName());

    /**
     * 构造函数
     *
     * @param context 上下文
     */
    public BaseProgressView(Context context) {
        super(context);
        init(context);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet 属性集合
     */
    public BaseProgressView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        initTypedArray(context, attrSet);
        init(context);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet 属性集合
     * @param styleName 样式
     */
    public BaseProgressView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context);
    }

    private void initTypedArray(Context context, AttrSet attrs) {
        progress = (int) getFloat(attrs, "progress", progress);
        strokeWidth = getDimension(attrs, "stroke_width", strokeWidth);
        backgroundStrokeWidth = getDimension(attrs, "background_stroke_width", backgroundStrokeWidth);
        color = getColor(attrs, "progress_color", color);
        backgroundColor = getColor(attrs, "background_color", backgroundColor);
        textColor = getColor(attrs, "text_color", textColor);
        textSize = (int) getDimension(attrs, "text_size", textSize);
        typeFace = createFontBuild(context, facePath);
    }

    /**
     * 初始化背景色
     */
    protected void initBackgroundColor() {
        backgroundPaint = new Paint();
        backgroundPaint.setAntiAlias(true);
        backgroundPaint.setColor(backgroundColor);
        backgroundPaint.setStyle(Paint.Style.STROKE_STYLE);
        backgroundPaint.setStrokeWidth(backgroundStrokeWidth);
        if (isRoundEdge) {
            backgroundPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        }
        if (isShadowed) {
            backgroundPaint.setBlurDrawLooper(new BlurDrawLooper(DEFAULT_RADIUS, 0.0f, 2.0f, shadowColor));
        }
    }

    /**
     * 初始化前景色
     */
    protected void initForegroundColor() {
        foregroundPaint = new Paint();
        foregroundPaint.setAntiAlias(true);
        foregroundPaint.setColor(color);
        foregroundPaint.setStyle(Paint.Style.STROKE_STYLE);
        foregroundPaint.setStrokeWidth(strokeWidth);
        if (isRoundEdge) {
            foregroundPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        }
        if (isShadowed) {
            foregroundPaint.setBlurDrawLooper(new BlurDrawLooper(DEFAULT_RADIUS, 0.0f, 2.0f, shadowColor));
        }
    }

    /**
     * 初始化颜色
     */
    protected void initTextColor() {
        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setDither(true);
        textPaint.setColor(textColor);
        textPaint.setStyle(Paint.Style.FILLANDSTROKE_STYLE);
        textPaint.setStrokeWidth(1f);
        textPaint.setTextSize(textSize);
        typeFace = createFontBuild(mContext, facePath);
        textPaint.setFont(typeFace);
    }

    /**
     * 获取进度
     *
     * @return 进度
     */
    public float getProgress() {
        return progress;
    }

    /**
     * 设置进度
     *
     * @param progress 进度
     */
    public void setProgress(int progress) {
        setProgressInView(progress);
    }

    private synchronized void setProgressInView(int progress) {
        this.progress = (progress <= maxProgress) ? progress : maxProgress;
        invalidate();
        trackProgressInView(progress);
    }

    private void trackProgressInView(int progress) {
        if (listener != null) {
            listener.onProgressUpdate(progress);
            if (progress >= maxProgress) {
                listener.onProgressFinish();
            }
        }
    }

    /**
     * 重置进度
     */
    public void resetProgress() {
        setProgress(0);
    }

    /**
     * 设置字体大小
     *
     * @param textSize 字体大小
     */
    public void setTextSize(int textSize) {
        this.textSize = textSize;
        init(mContext);
    }

    /**
     * 设置字体
     *
     * @param typefacePath 字体
     */
    public void setTypeface(String typefacePath) {
        this.facePath = typefacePath;
        init(mContext);
    }

    /**
     * 获取进度条颜色
     *
     * @return 进度条颜色值
     */
    public Color getProgressColor() {
        return color;
    }

    /**
     * 设置进度条颜色
     *
     * @param proColor 颜色
     */
    public void setProgressColor(Color proColor) {
        this.color = proColor;
        init(mContext);
    }

    /**
     * 获取进度条背景色
     *
     * @return 背景色
     */
    public Color getBackgroundColor() {
        return backgroundColor;
    }

    /**
     * 设置进度条背景色
     *
     * @param backgroundColor 背景色
     */
    public void setBackgroundColor(Color backgroundColor) {
        this.backgroundColor = backgroundColor;
        init(mContext);
    }

    /**
     * 获取字体颜色
     *
     * @return 文本颜色
     */
    public Color getTextColor() {
        return textColor;
    }

    /**
     * 设置字体文本颜色
     *
     * @param textColor 文本颜色
     */
    public void setTextColor(Color textColor) {
        this.textColor = textColor;
        init(mContext);
    }

    /**
     * 设置进度条宽度
     *
     * @param strokeWidth 进度条宽度
     */
    public void setProgressStrokeWidth(int strokeWidth) {
        this.strokeWidth = strokeWidth;
        init(mContext);
    }

    /**
     * 设置背景进度条宽度
     *
     * @param strokeWidth 宽度
     */
    public void setBackgroundStrokeWidth(int strokeWidth) {
        this.backgroundStrokeWidth = strokeWidth;
        init(mContext);
    }

    /**
     * 设置线帽是否开启圆形
     *
     * @param isRoundEdge true 开启 false 关闭
     */
    public void setRoundEdge(boolean isRoundEdge) {
        this.isRoundEdge = isRoundEdge;
        init(mContext);
    }

    /**
     * 设置是否开启阴影
     *
     * @param isShadowed 是否开启阴影
     */
    public void setShadow(boolean isShadowed) {
        this.isShadowed = isShadowed;
        init(mContext);
    }

    /**
     * 初始化
     *
     * @param context 上下文
     */
    protected abstract void init(Context context);

    /**
     * 设置进度监听
     *
     * @param onProgressTrackListener 进度监听
     */
    public void setOnProgressTrackListener(OnProgressTrackListener onProgressTrackListener) {
        this.listener = onProgressTrackListener;
    }

    /**
     * 读取 xml 尺寸型属性
     *
     * @param attrSet 属性集合
     * @param key 属性键
     * @param defDimensionValue 默认值
     * @return 属性值
     */
    private float getDimension(AttrSet attrSet, String key, float defDimensionValue) {
        if (!attrSet.getAttr(key).isPresent()) {
            return defDimensionValue;
        }
        Attr attr = attrSet.getAttr(key).get();
        return attr.getDimensionValue();
    }

    /**
     * 读取 xml 尺寸型属性
     *
     * @param attrSet 属性集合
     * @param key 属性键
     * @param defDimensionValue 默认值
     * @return 属性值
     */
    private float getFloat(AttrSet attrSet, String key, int defDimensionValue) {
        if (!attrSet.getAttr(key).isPresent()) {
            return defDimensionValue;
        }
        Attr attr = attrSet.getAttr(key).get();
        return attr.getFloatValue();
    }

    /**
     * 读取 xml 尺寸型属性
     *
     * @param attrSet 属性集合
     * @param key 属性键
     * @param defDimensionValue 默认值
     * @return 属性值
     */
    private int getInt(AttrSet attrSet, String key, int defDimensionValue) {
        if (!attrSet.getAttr(key).isPresent()) {
            return defDimensionValue;
        }
        Attr attr = attrSet.getAttr(key).get();
        return attr.getIntegerValue();
    }

    /**
     * 读取 xml 颜色属性
     *
     * @param attrSet 属性集合
     * @param key 属性键
     * @param defValue 默认值
     * @return 属性值
     */
    private Color getColor(AttrSet attrSet, String key, Color defValue) {
        if (attrSet.getAttr(key).isPresent()) {
            return attrSet.getAttr(key).get().getColorValue();
        } else {
            return defValue;
        }
    }

    /**
     * 创建字体
     *
     * @param context 上下文
     * @param name 字体名称
     * @return Font 字体
     */
    private Font createFontBuild(Context context, String name) {
        ResourceManager resManager = context.getResourceManager();
        RawFileEntry rawFileEntry = resManager.getRawFileEntry("resources" + File.separator + "rawfile" + File.separator + name);
        Resource resource = null;
        OutputStream outputStream = null;
        File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), new StringBuffer(name).toString());
        try {
            resource = rawFileEntry.openRawFile();
            outputStream = new FileOutputStream(file);
            int index;
            byte[] bytes = new byte[BYTE];
            while ((index = resource.read(bytes)) != DEFAULT_NUMBER) {
                outputStream.write(bytes, 0, index);
                outputStream.flush();
            }
        } catch (IOException e) {
            HiLog.debug(mTag, "%{public}s ", HiLog.getStackTrace(e));
        } finally {
            try {
                if (outputStream != null) {
                    resource.close();
                    outputStream.close();
                }
            } catch (IOException e) {
                HiLog.debug(mTag, "%{public}s ", HiLog.getStackTrace(e));
            }
        }
        Font.Builder builder = new Font.Builder(file);
        return builder.build();
    }
}
